package fun.cyhgraph.service.serviceImpl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import fun.cyhgraph.common.ErrorCode;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import fun.cyhgraph.common.UserConstant;
import fun.cyhgraph.exception.ThrowUtils;
import fun.cyhgraph.model.dto.*;
import fun.cyhgraph.model.entity.User;
import fun.cyhgraph.exception.BusinessException;
import fun.cyhgraph.mapper.UserMapper;
import fun.cyhgraph.properties.WeChatProperties;
import fun.cyhgraph.result.Result;
import fun.cyhgraph.service.UserService;
import fun.cyhgraph.utils.HttpClientUtil;
import fun.cyhgraph.utils.SqlUtils;
import fun.cyhgraph.model.vo.UserLoginVO;
import fun.cyhgraph.utils.verifyUtil;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;


import static fun.cyhgraph.common.UserConstant.USER_LOGIN_STATE;
import jakarta.annotation.Resource;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    // 微信服务接口地址
    public static final String WX_LOGIN = "https://api.weixin.qq.com/sns/jscode2session";
    public static final String SALT = "rush";
    @Value("${hanye.wechat.appid}")
    private String appId;
    @Value("${hanye.wechat.secret}")
    private String appSecret;
    @Resource
    private WeChatProperties weChatProperties;
    @Resource
    private UserMapper userMapper;


    /**
     * 用户微信登录
     *
     * @return
     */
    public Result<Object> wxLogin(UserLoginWechatDTO userLoginWechatDTO , HttpServletRequest request) {
        // 调用私有方法，其中利用HttpClient来调用微信API服务，获取openid
        String openid = getOpenId(userLoginWechatDTO.getCode());
        // 判断openid是否为空，如果为空表示登录失败，抛出业务异常
        ThrowUtils.throwIf(StringUtils.isBlank(openid), ErrorCode.PARAMS_ERROR, "openid为空");
        // 判断当前用户是否为新用户
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getOpenid , openid);
        User user = this.getOne(lambdaQueryWrapper);
        // 如果是新用户，自动完成注册，插入到数据库
        if(user == null){
            User user1 = new User();
            user1.setOpenid(openid);
            user1.setCreateTime(LocalDateTime.now());
            user1.setStatus(0);
            user1.setRole(UserConstant.USER_ROLE);

            boolean save = this.save(user1);
            if (!save){
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "注册失败");
            }
            request.getSession().setAttribute(USER_LOGIN_STATE, user1);
            return Result.success("操作成功（注册并登录）");
        }
        // 3. 记录用户的登录态
        request.getSession().setAttribute(USER_LOGIN_STATE, user);
        return Result.success("操作成功");
    }


    /**
     * 根据id查询用户
     * @param id
     * @return
     */
    public User getUser(Integer id) {
        return userMapper.getById(id);
    }

    /**
     * 修改用户信息
     * @param userDTO
     */
    public void update(UserDTO userDTO) {
        User user = new User();
        BeanUtils.copyProperties(userDTO, user);
        userMapper.update(user);
    }

    @Override
    public void verifyAdmin (UserRegisterForAdminDTO userRegisterDTO) {
        String name = userRegisterDTO.getName();
        String password = userRegisterDTO.getPassword();
        String phone = userRegisterDTO.getPhone();

        // 1. 校验
        if (StringUtils.isAnyBlank(name, password )) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "请完善上述参数");
        }
        //校验手机号是否合法
        if(!verifyUtil.isValidPhoneNumber(phone)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "手机号不合法");
        }
        if (name.length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号过短");
        }
        if (password.length() < 8) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户密码过短");
        }

        synchronized (phone.intern()) {
            // 账户不能重复
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("phone", phone);
            //查询
            long count = this.count(queryWrapper);
            if (count > 0) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "一个手机号只能绑定一名用户哦！");
            }
            // 用户名不能重复
            QueryWrapper<User> queryWrapper1 = new QueryWrapper<>();
            queryWrapper.eq("name", name);
            //查询
            long count1 = this.count(queryWrapper);
            if (count1 > 0) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "账户名已存在，请试试别的吧");
            }
        }
    };
    @Override
    public void verifyMerchant (RegisterForMerchantDTO userRegisterDTO) {
        String name = userRegisterDTO.getName();
        String password = userRegisterDTO.getPassword();
        String phone = userRegisterDTO.getPhone();
        // 1. 校验
        if (StringUtils.isAnyBlank(name, password, phone )) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "请完善上述参数");
        }
        //校验手机号是否合法
        if(!verifyUtil.isValidPhoneNumber(phone)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "手机号不合法");
        }

        if (name.length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号过短");
        }
        //name必须为英文或数字或数字英文结合
        if(!verifyUtil.isValidEnglish(name)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户名必须为英文或数字");
        }

        synchronized (phone.intern()) {
            // 账户不能重复
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("phone", phone);
            //查询
            long count = this.count(queryWrapper);
            if (count > 0) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "一个手机号只能绑定一名用户哦！");
            }
            // 用户名不能重复
            QueryWrapper<User> queryWrapper1 = new QueryWrapper<>();
            queryWrapper.eq("name", name);
            //查询
            long count1 = this.count(queryWrapper);
            if (count1 > 0) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "账户名已存在，请试试别的吧");
            }
        }
    };
    @Override
    public void verifyRider (UserRegisterForAdminDTO userRegisterDTO) {
        String name = userRegisterDTO.getName();
        String password = userRegisterDTO.getPassword();
        String phone = userRegisterDTO.getPhone();
        // 1. 校验
        if (StringUtils.isAnyBlank(name, password, phone )) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "请完善必填参数");
        }
        //校验name
        if(!verifyUtil.isValidEnglish(name)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户名必须为英文或数字");
        }
        if (name.length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号过短");
        }
        //校验手机号是否合法
        if(!verifyUtil.isValidPhoneNumber(phone)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "手机号不合法");
        }
        if (password.length() < 8) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户密码过短");
        }
        synchronized (phone.intern()) {
            // 账户不能重复
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("phone", phone);
            //查询
            long count = this.count(queryWrapper);
            if (count > 0) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "一个手机号只能绑定一名用户哦！");
            }
            // 用户名不能重复
            LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(User::getName, name);
            if (this.count(lambdaQueryWrapper) > 0) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户名已存在，请试试别的吧");
            }
        }
    };

    @Override
    public UserLoginVO userLogin(String name, String password, HttpServletRequest request) {
        String encryptPassword = DigestUtils.md5DigestAsHex((SALT + password).getBytes());
        // 查询用户是否存在
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", name);
        queryWrapper.eq("password", encryptPassword);
        queryWrapper.eq("status" , 0);
        User user = getOne(queryWrapper);
        // 用户不存在
        if (user == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户不存在或密码错误");
        }
        // 3. 记录用户的登录态
        request.getSession().setAttribute(USER_LOGIN_STATE, user);
        return this.getLoginUserVO(user);
    }
    @Override
    public UserLoginVO getLoginUserVO(User user) {
        if (user == null) {
            return null;
        }
        UserLoginVO loginUserVO = new UserLoginVO();
        BeanUtils.copyProperties(user, loginUserVO);
        return loginUserVO;
    }

    @Override
    public boolean userLogout(HttpServletRequest request) {
        if (request.getSession().getAttribute(USER_LOGIN_STATE) == null) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "未登录");
        }
        // 移除登录态
        request.getSession().removeAttribute(USER_LOGIN_STATE);
        return true;
    }

    @Override
    public User getLoginUser(HttpServletRequest request) {
        // 先判断是否已登录
        Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
        User currentUser = (User) userObj;
        if (currentUser == null || currentUser.getId() == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR , "未登录");
        }
        // 从数据库查询（追求性能的话可以注释，直接走缓存）
        long userId = currentUser.getId();
        currentUser = this.getById(userId);
        if (currentUser == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }
        return currentUser;
    }
    @Override
    public User getLoginUser(HttpServletRequest request , String message) {
        // 先判断是否已登录
        Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
        User currentUser = (User) userObj;
        if (currentUser == null || currentUser.getId() == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR , message);
        }
        // 从数据库查询（追求性能的话可以注释，直接走缓存）
        long userId = currentUser.getId();
        currentUser = this.getById(userId);
        if (currentUser == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }
        return currentUser;
    }

    @Override
    public QueryWrapper<User> getQueryWrapper(UserQueryRequest userQueryRequest) {
        if (userQueryRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "请求参数为空");
        }
        String name = userQueryRequest.getName();
        String phone = userQueryRequest.getPhone();
        String role = userQueryRequest.getRole();
        String sortOrder = userQueryRequest.getSortOrder();
        String sortField = userQueryRequest.getSortField();
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(StringUtils.isNotBlank(name), "name", name);
        queryWrapper.eq(StringUtils.isNotBlank(phone), "phone", phone);
        queryWrapper.like(StringUtils.isNotBlank(role), "role", role);
        queryWrapper.orderBy(SqlUtils.validSortField(sortField), sortOrder.equals(CommonConstant.SORT_ORDER_ASC),
                sortField);
        return queryWrapper;
    }

    @Override
    public Result<Object> wxLoginForRider(UserLoginWechatDTO userLoginWechatDTO) {
        // 调用私有方法，其中利用HttpClient来调用微信API服务，获取openid
        String openid = getOpenId(userLoginWechatDTO.getCode());
        // 判断openid是否为空，如果为空表示登录失败，抛出业务异常
        ThrowUtils.throwIf(StringUtils.isBlank(openid), ErrorCode.PARAMS_ERROR, "openid为空");
        // 判断当前用户是否为新用户
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getOpenid , openid);
        User user = this.getOne(lambdaQueryWrapper);
        // 如果是新用户，自动完成注册，插入到数据库
        if(user == null){
            return Result.error("对不起，您不是骑手，无法登录");
        }
        return Result.success("登录成功");
    }

    @Override
    public Result<Object> wxLoginForMerchant(UserLoginWechatDTO userLoginWechatDTO) {
        // 调用私有方法，其中利用HttpClient来调用微信API服务，获取openid
        String openid = getOpenId(userLoginWechatDTO.getCode());
        // 判断openid是否为空，如果为空表示登录失败，抛出业务异常
        ThrowUtils.throwIf(StringUtils.isBlank(openid), ErrorCode.PARAMS_ERROR, "openid为空");
        // 判断当前用户是否为新用户
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getOpenid , openid);
        User user = this.getOne(lambdaQueryWrapper);
        // 如果是新用户，自动完成注册，插入到数据库
        if(user == null){
            return Result.error("对不起，您还不是商家，无法登录");
        }
        return Result.success("登录成功");
    }


    /**
     * 调用微信接口服务，获取微信用户的openid
     * 4参数： appid secret(在小程序平台查看，忘了就重置) 临时登录凭证code 常量authorization_code
     * @param code
     * @return
     */
    private String getOpenId(String code) {
        // 调用微信接口服务，获得当前微信用户的openid
        Map<String, String> map = new HashMap<>();
        map.put("appid", weChatProperties.getAppid());
        map.put("secret", weChatProperties.getSecret());
        map.put("js_code", code);
        map.put("grant_type", "authorization_code");
        // 利用HttpClient来调用微信的API服务，得到序列化好的json
        String json = HttpClientUtil.doGet(WX_LOGIN, map); // 需自定义HttpClientUtil工具类
        // 解析返回的json对象，并抽取其中的openid
        JSONObject jsonObject = JSON.parseObject(json);
        String openid = jsonObject.getString("openid");
        return openid;
    }
}
